﻿using Microsoft.AspNetCore.Mvc;
namespace LogFileSystem.Controllers
{
    [ApiController]
    [Route("api/logs")]
    public class LogsController : ControllerBase
    {
        // 日志根目录（项目目录下的Logs文件夹）
        private readonly string _logRootPath;

        public LogsController()
        {
            // 获取项目根目录下的Logs文件夹路径
            _logRootPath = Path.Combine(AppContext.BaseDirectory, "Logs");

            // 确保日志目录存在
            if (!Directory.Exists(_logRootPath))
            {
                Directory.CreateDirectory(_logRootPath);
            }
        }

        /// <summary>
        /// 获取指定路径下的目录和文件列表（支持多层嵌套）
        /// </summary>
        [HttpGet("directory")]
        public IActionResult GetDirectoryContent([FromQuery] string path = "")
        {
            try
            {
                // 构建完整路径
                var fullPath = string.IsNullOrEmpty(path)
                    ? _logRootPath
                    : Path.Combine(_logRootPath, path);

                // 安全验证：确保在日志根目录内
                if (!IsPathWithinRoot(fullPath))
                {
                    return BadRequest(new { message = "无效的路径，不允许访问日志目录外的内容" });
                }

                // 验证路径是否存在
                if (!Directory.Exists(fullPath))
                {
                    return NotFound(new { message = "指定的目录不存在" });
                }

                // 获取所有子目录
                var directories = Directory.GetDirectories(fullPath)
                    .Select(dir => new
                    {
                        name = Path.GetFileName(dir),
                        isDirectory = true
                    })
                    .OrderBy(d => d.name)
                    .ToList();

                // 获取所有日志文件（可根据需要过滤文件类型，如只保留.log文件）
                var files = Directory.GetFiles(fullPath)
                    .Select(file => new
                    {
                        name = Path.GetFileName(file),
                        isDirectory = false,
                        fileSize = new FileInfo(file).Length,
                        lastWriteTime = System.IO.File.GetLastWriteTime(file)
                    })
                    .OrderByDescending(f => f.lastWriteTime) // 最新的文件排在前面
                    .ToList();

                // 合并目录和文件，目录在前
                var items = directories.Cast<object>().Concat(files).ToList();

                return Ok(new { items });
            }
            catch (Exception ex)
            {
                return StatusCode(StatusCodes.Status500InternalServerError,
                    new { message = "获取目录内容失败", error = ex.Message });
            }
        }

        /// <summary>
        /// 读取日志文件内容（支持部分加载）
        /// </summary>
        [HttpGet("content")]
        public IActionResult GetLogContent([FromQuery] string dir = "", [FromQuery] string file = "", [FromQuery] int? maxLines = 1000)
        {
            try
            {
                // 验证文件名是否有效
                if (string.IsNullOrEmpty(file))
                {
                    return BadRequest(new { message = "文件名不能为空" });
                }

                // 构建完整文件路径
                var directoryPath = string.IsNullOrEmpty(dir) ? _logRootPath : Path.Combine(_logRootPath, dir);
                var filePath = Path.Combine(directoryPath, file);

                // 安全验证：确保文件在日志目录内
                if (!IsPathWithinRoot(filePath))
                {
                    return BadRequest(new { message = "无效的文件路径" });
                }

                // 验证文件是否存在
                if (!System.IO.File.Exists(filePath))
                {
                    return NotFound(new { message = $"日志文件 {file} 不存在" });
                }

                // 读取文件内容（大文件优化：只读取最后maxLines行）
                var content = ReadLogFileContent(filePath, maxLines ?? 1000);

                return Ok(new
                {
                    content,
                    lineCount = content.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries).Length
                });
            }
            catch (Exception ex)
            {
                return StatusCode(StatusCodes.Status500InternalServerError,
                    new { message = "读取日志内容失败", error = ex.Message });
            }
        }

        /// <summary>
        /// 下载日志文件
        /// 请求示例：  https://localhost:7081/api/logs/download?dir=BasicManagement\Info&file=Info2025082820.log
        /// </summary>
        [HttpGet("download")]
        public IActionResult DownloadLogFile([FromQuery] string dir = "", [FromQuery] string file = "")
        {
            try
            {
                // 验证文件名是否有效
                if (string.IsNullOrEmpty(file))
                {
                    return BadRequest(new { message = "文件名不能为空" });
                }

                // 构建完整文件路径
                var directoryPath = string.IsNullOrEmpty(dir) ? _logRootPath : Path.Combine(_logRootPath, dir);
                var filePath = Path.Combine(directoryPath, file);

                // 安全验证
                if (!IsPathWithinRoot(filePath) || !System.IO.File.Exists(filePath))
                {
                    return NotFound(new { message = $"日志文件 {file} 不存在" });
                }

                // 读取文件流（允许同时读取和写入）
                var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);


                    return File(fileStream, "text/plain", file);



                // 返回文件供下载
            }
            catch (Exception ex)
            {
                return StatusCode(StatusCodes.Status500InternalServerError,
                    new { message = "下载日志文件失败", error = ex.Message });
            }
        }

        /// <summary>
        /// 安全验证：确保文件路径在日志根目录内
        /// </summary>
        private bool IsPathWithinRoot(string filePath)
        {
            var fullRootPath = Path.GetFullPath(_logRootPath);
            var fullFilePath = Path.GetFullPath(filePath);

            return fullFilePath.StartsWith(fullRootPath, StringComparison.OrdinalIgnoreCase);
        }

        /// <summary>
        /// 读取日志文件内容（大文件优化）
        /// </summary>
        private string ReadLogFileContent(string filePath, int maxLines)
        {
            // 对于大文件，只读取最后N行，避免内存溢出
            if (new FileInfo(filePath).Length > 1024 * 1024 * 5) // 大于5MB的文件
            {
                return ReadLastLines(filePath, maxLines);
            }

            // 小文件直接读取全部内容
            return System.IO.File.ReadAllText(filePath);
        }

        /// <summary>
        /// 读取文件的最后N行
        /// </summary>
        private string ReadLastLines(string filePath, int lineCount)
        {
            if (lineCount <= 0)
                return "";

            using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            using (var sr = new StreamReader(fs))
            {
                byte[] buffer = new byte[1024];
                long position = fs.Length;
                int bytesRead;
                int linesFound = 0;
                string result = "";

                while (position > 0 && linesFound < lineCount)
                {
                    // 确保step不超过缓冲区长度和剩余字节数
                    int step = (int)Math.Min(buffer.Length, position);
                    if (step <= 0)
                        break; // 避免无效的step值

                    position -= step;
                    fs.Position = position;

                    // 读取数据
                    bytesRead = fs.Read(buffer, 0, step);
                    if (bytesRead == 0)
                        break; // 已到达文件开头

                    // 从后往前查找换行符
                    for (int i = bytesRead - 1; i >= 0; i--)
                    {
                        if (buffer[i] == '\n')
                        {
                            linesFound++;
                            if (linesFound == lineCount)
                            {
                                // 读取从当前位置到文件末尾的内容
                                fs.Position = position + i + 1;
                                result = sr.ReadToEnd();
                                return result;
                            }
                        }
                    }
                }

                // 如果文件行数不足，读取全部内容
                if (linesFound < lineCount)
                {
                    fs.Position = 0;
                    result = sr.ReadToEnd();
                }

                return result;
            }
        }
    }
}
